<template>
  <div class="panelBody">
    <div class="header">
      <el-select v-model="mySelectType" style="width: 100px">
        <el-option label="属性" value="propList"></el-option>
        <el-option label="表单属性" value="formItemPropsList"></el-option>
        <el-option label="事件" value="eventList"></el-option>
        <el-option label="样式" value="styleList"></el-option>
      </el-select>
      <el-autocomplete
        class="inline-input"
        style="width: 150px"
        v-model="myCurProp"
        :fetch-suggestions="querySearch"
        placeholder="请输入内容"
        clearable
      ></el-autocomplete>
      <el-button
        type="primary"
        @click="mySave"
        tabindex="0"
        @keydown.enter="mySave"
        >保存</el-button
      >
      <el-button type="success" @click="myCancel">重置</el-button>
    </div>
    <div
      id="myEditor"
      class="myEditor"
      :style="{ height: myCurProp !== 'globalStyle' ? '22%' : '64%' }"
    ></div>
    <div
      id="_myEditor"
      class="_myEditor"
      :style="{ height: myCurProp === 'globalStyle' ? '22%' : '64%' }"
    ></div>
  </div>
</template>

<script setup lang="ts">
// @ts-nocheck

import $store from "@/stores/counter"
import monaco from "../utils/userWorker"
import {
  toCamelCase,
  deepClone,
  getCustomConfig,
  debounce
} from "../utils/utils"
let store = $store().state
const myProps = defineProps({
  curCom: {
    type: Object,
    default: () => {
      return {
        span: 4,
        comName: "ElButton",
        type: "warning",
        style: "width: 60px",
        onClick: () => {
          alert("myCancel")
        },
        //onClick: myCancelIcon("svgBody", "svg"),

        contentText: "清除"
      }
    }
  },
  type: {
    type: String,
    default: "com"
  }
})
const myCurCom = ref({})
const initMyStateCurCom = (nv, initList = true) => {
  if (nv && nv.selfIndex) {
    let type = nv.selfIndex.split("_")[0]
    if (type !== "form" && type !== "row") type = "com"
    myState.comType = type
    myCurProp.value = ""
    myCurCom.value = nv
    if (initList) myInitList()
    myResetField()
  }
}
watch(
  () => myProps.curCom,
  (nv) => {
    initMyStateCurCom(nv)
  }
)
watch(
  () => store.curRow,
  (nv) => {
    nv && initMyStateCurCom(nv)
  }
)
const myState = reactive({
  eventList: [],
  propList: [],
  styleList: [
    { value: "globalStyle" },
    { value: "style" },
    { value: "_style" }
  ],
  formItemPropsList: [],
  comType: "com",
  // curCom: {},
  suggestions: [],
  saveEvent: false,
  curEditor: "com",
  lessContent: ""
})
const initSuggestion = ({ value }) => {
  let item = {
    label: value,
    kind: monaco.languages.CompletionItemKind.Keyword,
    insertText: '"' + value + '"',
    documentation: "keyword"
  }
  return item
}

const ctx = getCurrentInstance()
const mySelectType = ref("propList")
const myCurProp = ref("")
const querySearch = (queryString: string, cb: any) => {
  var list = myState[mySelectType.value] ?? []
  var results = queryString ? list.filter(createFilter(queryString)) : list
  // 调用 callback 返回建议列表的数据
  cb(results)
}
const createFilter = (queryString: string) => {
  return (ele: any) => {
    return ele.value.toLowerCase().indexOf(queryString.toLowerCase()) >= 0
  }
}
const mySave = () => {
  //////待改

  if (myCurProp.value === "globalStyle") {
    const lessStyle = document.getElementById("styleDom")
    // const lessContent = lessStyle.innerHTML
    // myState.lessContent = str
    //!todo
    if (window.less && lessStyle)
      window.less.render(myState.lessContent, (error, output) => {
        if (!error) {
          console.log(output)

          // 将编译后的 CSS 应用于样式表标签
          // const cssStyle = document.createElement("style")
          // cssStyle.type = "text/css"
          // const head = document.getElementsByTagName("head")[0]
          // head.appendChild(cssStyle)

          if (lessStyle.styleSheet) {
            lessStyle.styleSheet.cssText = output.css
          } else {
            lessStyle.appendChild(document.createTextNode(output.css))
          }
        }
      })
    return
  }
  ctx?.emit("changeProp", myCurCom.value)
}
const mySaveProp = () => {
  if (myState.curEditor !== "prop") return
  let str = myEditor.getValue()
  if (str === "" || !str || !myCurProp.value || myCurProp.value === "") return
  let val

  try {
    val = JSON.parse(str)
    //'{ "prop": "", "formProp": "", "label": ""}'
  } catch (error) {
    try {
      val = eval(str)
      val = str ////方法保存字符串格式
      // ;() => {
      //   alert("myCancel")
      // }
    } catch (err) {
      //////////global?
      //'div{\r\n    background-color: red;\r\n}'
      //'form.test==1?2:3'
      //'myCurProp1'
      val = str
      if (myCurProp.value === "style") {
        str = str.includes("{")
          ? str.match(/\{([^}]*)\}/)[1].replace(/\r?\n|\r/g, "") ?? ""
          : str
        val = str
      }
      if (myCurProp.value === "globalStyle") {
        // const lessStyle = document.getElementById("styleDom")
        // const lessContent = lessStyle.innerHTML
        myState.lessContent = str
      }
    }
  }
  let prop = myCurProp.value
  // if (mySelectType.value.includes("event") && !prop.startsWith("on")) {
  //   prop = toCamelCase("on-" + prop)
  // }
  myCurCom.value[prop] = val
}
const myCancel = () => {
  initMyStateCurCom(myProps.curCom, false)
}

const resetLanguage = () => {
  let newVal = null

  if (mySelectType.value.includes("style")) {
    switch (myCurProp.value) {
      case "globalStyle":
        newVal = "less"
        break
      case "_style":
        newVal = "javascript"
        break
      default:
        newVal = "css"
        break
    }
  } else {
    newVal = "javascript"
  }
  if (newVal !== myEditor.getModel().getLanguageId()) {
    monaco.editor.setModelLanguage(myEditor.getModel(), newVal)
    myEditor.setValue("")
  }
}
const myResetField = (formatter = true) => {
  ////////////global????
  let val = ""
  let com = myCurCom.value
  let myprop = myCurProp.value
  let list = myState[mySelectType.value]
  let item = list.find((e) => {
    if (e.value === myCurProp.value) return true
  })
  let defautVal = undefined
  if (item) defautVal = item.default
  let flg = defautVal !== undefined
  // if (
  //   mySelectType.value.includes("event") &&
  //   !myprop.startsWith("on") &&
  //   !myprop.startsWith("_on")
  // ) {
  //   myprop = "_" + toCamelCase("on-" + myprop)
  //   defautVal = flg ? defautVal : () => {}
  // }
  if (myCurProp.value === "style") {
    defautVal = flg ? defautVal : ".{\n\t\r}"
    if (!flg) formatter = false
  }
  if (mySelectType.value === "formItemPropsList") {
    if (!com["formItemProps"]) com["formItemProps"] = {}
    val = com["formItemProps"][myprop] ?? ""
  } else val = com[myprop] ?? defautVal ?? ""

  let strVal = val
  if (typeof val === "function") strVal = val.toString()
  if (typeof val === "object") strVal = JSON.stringify(val)
  if (typeof val === "string" && val !== "") strVal = '"' + strVal + '"'
  strVal += ""
  if (myprop === "globalStyle") {
    strVal = myState.lessContent
  }
  myEditor.setValue(strVal)
  if (formatter)
    nextTick(() => {
      myEditor.getAction("editor.action.formatDocument").run()
    })
}
const resetSuggestions = () => {
  monaco.languages.registerCompletionItemProvider("json", {
    provideCompletionItems: function (model, position) {
      return {
        suggestions: myState.suggestions.filter(function (item) {
          return (
            item.label.indexOf(model.getWordUntilPosition(position).word) !== -1
          )
        })
      }
    }
  })
}
const myInitList = () => {
  myState.propList = []
  myState.eventList = []
  myState.formItemPropsList = []
  myState.suggestions = []
  const name = myCurCom.value?.comName
  let com = window._customComponents[name] ?? {}
  Object.keys(com?.emits ?? {}).forEach((k) => {
    let nk = k
    if (k && !k.startsWith("on")) {
      nk = toCamelCase("on-" + nk)
    }
    myState.eventList.push({ value: nk })
    myState.eventList.push({ value: "_" + nk })
    myState.suggestions.push(initSuggestion({ value: "_" + nk }))
  })
  Object.keys(com?.props ?? {}).forEach((k) => {
    if (k) {
      let prop = com.props[k]
      let item = { value: k, isRequired: !!prop?.required, type: prop?.name }
      myState.propList.push(item)
      myState.suggestions.push(initSuggestion(item))
      myState.propList.push({ value: "_" + k, type: prop?.name, default: "" })
      myState.suggestions.push(
        initSuggestion({ value: "_" + k, type: prop?.name, default: "" })
      )
    }
  })
  let customConf = getCustomConfig()
  let customProps = customConf[myState.comType]?.prop ?? {}
  Object.keys(customProps).forEach((k) => {
    myState.propList.push({
      value: k,
      default: customProps[k]?.default ?? undefined,
      type: customProps[k].type
    })
    myState.suggestions.push(initSuggestion({ value: k }))

    myState.propList.push({
      value: "_" + k,
      default: "" ?? undefined,
      type: customProps[k].type
    })
    myState.suggestions.push(initSuggestion({ value: "_" + k }))
  })
  let formItemProps = customConf[myState.comType]?.formItemProps ?? {}
  Object.keys(formItemProps).forEach((k) => {
    myState.formItemPropsList.push({
      value: k,
      default: formItemProps[k]?.default ?? undefined,
      type: formItemProps[k].type
    })
    myState.suggestions.push(initSuggestion({ value: "_" + k }))
    myState.suggestions.push(initSuggestion({ value: k }))
    myState.formItemPropsList.push({
      value: "_" + k,
      default: "" ?? undefined,
      type: formItemProps[k].type
    })
  })
  let glbalProps = customConf.global
  Object.keys(glbalProps).forEach((k) => {
    myState.propList.push({
      value: k,
      default: glbalProps[k]?.default ?? undefined,
      type: glbalProps[k].type
    })
    myState.suggestions.push(initSuggestion({ value: "_" + k }))
    myState.suggestions.push(initSuggestion({ value: k }))
    myState.propList.push({
      value: "_" + k,
      default: "" ?? undefined,
      type: glbalProps[k].type
    })
  })
  resetSuggestions()
}
const resetLayout = debounce(() => {
  myEditor.layout()
  nextTick(() => _myEditor.layout())
}, 500)
const mySaveCurCom = () => {
  if (myState.curEditor !== "com") return
  myState.saveEvent = true
  try {
    let str = _myEditor.getValue()
    let val = JSON.parse(str)
    myCurCom.value = val
  } catch (error) {
    throw error
  }
}
watch(
  () => mySelectType.value,
  (nv) => {
    let list = myState[nv] ?? []
    myCurProp.value = list[0]?.value ?? ""
    if (!nv.includes("style")) resetLanguage()
  }
)
watch(
  () => myCurProp.value,
  (nv, ov) => {
    if (nv === "globalStyle" || ov === "globalStyle") {
      // nextTick(() => )
      setTimeout(() => {
        resetLayout()
      }, 800)
    }
    if (mySelectType.value.includes("style")) {
      resetLanguage()
    }
    myResetField()
  }
)

let myEditor: any
let _myEditor: any
const effect = markRaw(() => {
  let nv = myCurCom.value
  if (!_myEditor) return
  if (myState.saveEvent) {
    myState.saveEvent = false
    return
  }
  let obj = {}
  Object.keys(nv).forEach((k) => {
    if (typeof nv[k] === "function") {
      obj[k] = nv[k].toString()
    } else obj[k] = nv[k]
  })
  _myEditor.setValue(JSON.stringify(obj))
  nextTick(() => {
    _myEditor.getAction("editor.action.formatDocument").run()
  })
})
watchEffect(
  // () => myCurCom.value,
  effect
)
onMounted(() => {
  let dom = document.getElementById("myEditor")
  let dom1 = document.getElementById("_myEditor")
  myEditor = monaco.editor.create(dom, {
    value: "",
    language: "javascript",
    theme: "vs",
    validateOnType: false
  })
  _myEditor = monaco.editor.create(dom1, {
    value: JSON.stringify(myCurCom.value),
    language: "json",
    theme: "vs"
  })
  _myEditor.updateOptions({
    wordWrap: "on"
  })
  myEditor.updateOptions({
    wordWrap: "on"
  })
  myEditor.onDidBlurEditorText(() => {
    //失焦保存
    mySaveProp()
    // console.log("Editor lost focus")
    // 执行你需要的代码
  })
  _myEditor.onDidBlurEditorText(() => {
    //失焦保存
    mySaveCurCom()
    // console.log("Editor lost focus")
    // 执行你需要的代码
  })
  myEditor.onDidFocusEditorText(function () {
    // 编辑器获取焦点后触发的回调函数
    myState.curEditor = "prop"
  })
  _myEditor.onDidFocusEditorText(function () {
    // 编辑器获取焦点后触发的回调函数
    myState.curEditor = "com"
  })
})
onBeforeUnmount(() => {
  myEditor.dispose()
})
window.addEventListener("resize", function () {
  resetLayout()
})
myInitList()
</script>

<style lang="less" scoped>
.fullContent() {
  width: 100%;
  height: 100%;
}
.flexNormal() {
  width: 100%;
  height: 100%;
  display: flex;
}
.panelBody {
  border-left: 1px solid pink;
  flex-direction: column;
  position: relative;
  .flexNormal();
  .fullContent();
  .header {
    .flexNormal();
    height: fit-content;
    margin-bottom: 10px;
    justify-content: space-around;
  }
  .myEditor {
    // flex: 1;
    margin: 2px;
    // max-height: 450px;
  }
  ._myEditor {
    // flex: 1;
    // height: 75%;
    margin: 2px;
  }
}
</style>
